#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>
#include <sys/wait.h>

using namespace std;

//输出信号位图（注意：这里只是输出普通信号）
void PrintSig(sigset_t &pending)
{
    cout << "Pending bitmap: ";
    for (int signo = 31; signo > 0; signo--)
    {
        if (sigismember(&pending, signo))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

//查看信号递达中的pending位图
//注意：当指定信号开始递达时，该信号在进程中的pending位图就已经清0
void handler(int signo)
{
    //获取当前信号位图
    sigset_t pending;
    sigemptyset(&pending);
    int n = sigpending(&pending); 
    assert(n == 0);

    //打印pending位图中的收到的信号
    cout << "信号递达中的信号位图...: ";
    PrintSig(pending); 
    cout << signo << "信号被递达处理..." << endl;
}

int main()
{   
    //对2号信号进行自定义捕捉——不让进程因为2号信号而终止
    signal(2, handler);

    //屏蔽2号信号——将2号信号加入到信号集block
    sigset_t block, oblock;
    sigemptyset(&block); //初始化
    sigemptyset(&oblock); //初始化
    sigaddset(&block, 2); 

    //下面循环语句是屏蔽所有的普通信号（9号信号和19号信号无法被屏蔽，18号信号做特殊处理）
    // for(int signo = 1; signo <= 31; signo++) 
    //     sigaddset(&block, signo); 

    //开始屏蔽2号信号，其实就是设置进入内核中（这里把原本的信号屏蔽字存入oblock中）
    int n = sigprocmask(SIG_SETMASK, &block, &oblock);
    assert(n == 0);
    cout << "block 2 signal success" << endl;
    cout << "pid: " << getpid() << endl;
    int cnt = 0;
    while (true)
    {
        //获取进程的pending位图
        sigset_t pending;
        sigemptyset(&pending);
        n = sigpending(&pending);
        assert(n == 0);

        //打印pending位图中的收到的信号
        PrintSig(pending);
        cnt++;

        //解除对2号信号的屏蔽，这时会执行signal的2号信号处理方法
        if (cnt == 10)
        {
            cout << "解除对2号信号的屏蔽" << endl;
            n = sigprocmask(SIG_UNBLOCK, &block, &oblock); 
            assert(n == 0);
        }
        sleep(1);
    }

    return 0;
}


//进程中信号的状态
// int main()
// {
//     pid_t id = fork();
//     if(id == 0)
//     {
//         sleep(1);
//         int a = 10;
//         a /= 0; // 故意异常，收到SIGFPE-> core
//         exit(0);
//     }

//     // father
//     int status = 0;
//     pid_t rid = waitpid(id, &status, 0);
//     if(rid > 0)
//     {
//         cout << "exit code: " << ((status>>8) & 0xFF) << endl; //进程的退出状态，即退出码，没有意义
//         cout << "exit signal: " << (status & 0x7F) << endl;  //退出信号
//         cout << "core dump: " << ((status>>7) & 0x1) << endl; //core dump标志位
//     }
//     return 0;
// }
